#pragma once

#include <deque>
#include <mutex>
#include <memory>

namespace ccq {

template <typename T>
class SafeQueue {
public:
    using lock_guard_t = std::lock_guard<std::mutex>;

    SafeQueue(size_t capacity = 0) {
        if(capacity > 0)
            m_q.resize(capacity);
    }

    ~SafeQueue() = default;
    SafeQueue(const SafeQueue &) = delete;
    SafeQueue &operator=(const SafeQueue &) = delete;

    SafeQueue(SafeQueue &&other) {
        m_q.swap(other.m_q);
    }

    void push_back(const T &t) {
        lock_guard_t lock(m_mutex);
        m_q.emplace_back(t);
    }

    void push_back(T &&t) {
        lock_guard_t lock(m_mutex);
        m_q.emplace_back(std::move(t));
    }

    void push_front(const T &t) {
        lock_guard_t lock(m_mutex);
        m_q.emplace_front(t);
    }

    void push_front(T &&t) {
        lock_guard_t lock(m_mutex);
        m_q.emplace_front(std::move(t));
    }

    bool pop(T &t) {
        lock_guard_t lock(m_mutex);
        if(m_q.size() > 0) {
            t = std::move(m_q.front());
            m_q.pop_back();
            return true;
        }
        else {
            return false;
        }
    }

    size_t size() const {
        lock_guard_t lock(m_mutex);
        return m_q.size();
    }

    bool empty() const {
        return size() == 0;
    }

    void resize(size_t capacity) {
        lock_guard_t lock(m_mutex);
        return m_q.resize(capacity);
    }

private:
    std::deque<T> m_q;
    mutable std::mutex m_mutex;
};  // SafeQueue

} // namespace ccq